package ltd.dujiabao.inventoryservice.listener;

import lombok.extern.slf4j.Slf4j;
import ltd.dujiabao.inventoryservice.dao.ConsumedMessageRepository;
import ltd.dujiabao.inventoryservice.dao.InventoryRepository;
import ltd.dujiabao.inventoryservice.domain.entity.ConsumedMessage;
import ltd.dujiabao.inventoryservice.domain.enums.ConsumedResult;
import ltd.dujiabao.orderservice.domain.dto.OrderMessage;
import ltd.dujiabao.utils.JsonUtils;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * @author Bowie Du
 * @date 2025/7/12 19:05
 */
@Slf4j
@Component
public class InventoryListener {
    private static final String INVENTORY_QUEUE = "inventory";
    private static final String INVENTORY_EXCHANGE = "inventory";
    private static final String INVENTORY_ROUTING_KEY = "inventory";

    @Autowired
    private InventoryRepository inventoryRepository;

    @Autowired
    private ConsumedMessageRepository consumedMessageRepository;

    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(
                            value = INVENTORY_QUEUE,
                            durable = "true",
                            arguments = {
                                    @Argument(name = "x-dead-letter-exchange", value = INVENTORY_EXCHANGE + ".dlx"),
                                    @Argument(name = "x-dead-letter-routing-key", value = INVENTORY_ROUTING_KEY)
                            }),
                    exchange = @Exchange(
                            value = INVENTORY_EXCHANGE,
                            durable = Exchange.TRUE,
                            type = ExchangeTypes.DIRECT
                    ),
                    key = INVENTORY_ROUTING_KEY
            )
    )
    @Transactional(rollbackFor = Exception.class)
    public void onMessage(String message, MessageProperties properties) {
        String messageId = properties.getMessageId();
        OrderMessage dto = JsonUtils.fromJson(message, OrderMessage.class);
        log.info("received message: {}", messageId);
        // 消息幂等性
        if (consumedMessageRepository.existsByMessageId(messageId)) {
            log.info("messageId: {} has been consumed, ignore", messageId);
            return;
        }
        int effectRows = inventoryRepository.decreaseInventory(dto.getProductId(), dto.getQuantity());
        if (effectRows == 0) {
            log.error("messageId: {} decrease inventory failed.", messageId);
            ConsumedMessage consumedMessage = new ConsumedMessage()
                    .setMessageId(messageId)
                    .setResult(ConsumedResult.FAILED.getValue())
                    .setErrorMsg("decrease inventory failed")
                    .setCreatedAt(LocalDateTime.now())
                    .setUpdatedAt(LocalDateTime.now());
            consumedMessageRepository.save(consumedMessage);
        } else {
            ConsumedMessage consumedMessage = new ConsumedMessage()
                    .setMessageId(messageId)
                    .setResult(ConsumedResult.SUCCESS.getValue())
                    .setCreatedAt(LocalDateTime.now())
                    .setUpdatedAt(LocalDateTime.now());
            consumedMessageRepository.save(consumedMessage);
        }
    }

    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(
                            value = INVENTORY_QUEUE + ".dlq",
                            durable = "true"
                    ),
                    exchange = @Exchange(
                            value = INVENTORY_EXCHANGE + ".dlx",
                            durable = Exchange.TRUE,
                            type = ExchangeTypes.DIRECT),
                    key = INVENTORY_ROUTING_KEY
            )
    )
    public void onDeadLetterMessage(String message, MessageProperties properties) {
        String messageId = properties.getMessageId();
        log.error("dead letter message: {}", messageId);
        ConsumedMessage consumedMessage = new ConsumedMessage()
                .setMessageId(messageId)
                .setResult(ConsumedResult.FAILED.getValue())
                .setErrorMsg(JsonUtils.toJson(properties.getXDeathHeader()))
                .setCreatedAt(LocalDateTime.now())
                .setUpdatedAt(LocalDateTime.now());
        consumedMessageRepository.save(consumedMessage);
    }
}
